﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;
using SHomeWorkshop.LunarConcept.Adorners;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Enums;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;
using System.Collections.Generic;
using SHomeWorkshop.LunarMind;

namespace SHomeWorkshop.LunarConcept.Widgets
{
    /// <summary>
    /// 创建时间：2012年1月20日前
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：提供一个带文本的圆形（椭圆）。
    /// </summary>
    public class EllipseWidget : ShapeWidget, ICanSameSize, ICanBeLinkedWidget, ITextRotate
    {

        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态构造方法]
        /// </summary>
        static EllipseWidget()
        {
            dashArray = new DoubleCollection() { 2, 2 };
        }

        /// <summary>
        /// 构造方法。
        /// </summary>
        /// <param name="pageEditor">所属的PageEditor。此参数将成为Widget.MasterEditor的值。</param>
        public EllipseWidget(PageEditorReader pageEditor)
            : base(pageEditor)
        {
            widgetType = Enums.WidgetTypes.Ellipse;
            widgetClassLocalName = Widget.GetWidgetClassLocalName(this.GetType().Name);

            mainEllipse.Fill = null;
            mainEllipse.Stroke = WidgetForeColor;
            this.mainCanvas.Children.Add(mainEllipse);

            Canvas.SetZIndex(mainEllipse, 0);
            
            this.commentAdorner = new CommentAdorner(this.mainEllipse, this) { Visibility = System.Windows.Visibility.Collapsed };//默认不显示。

            this.hyperLinkAdorner = new HyperLinkAdorner(this.mainEllipse, this) { Visibility = Visibility.Collapsed };
            this.hyperLinkAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(hyperLinkAdorner_MouseLeftButtonUp);

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.mainCanvas);
            if (adornerLayer == null)
            {
                MessageBox.Show("　　未找到Widget的装饰层！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            else
            {
                adornerLayer.Add(this.commentAdorner);//这个要在各具体部件类中添加。
                adornerLayer.Add(this.hyperLinkAdorner);//这个要在各具体部件类中添加。
            }
            
            //最后添加文本面板。
            this.mainCanvas.Children.Add(this.mainTextPanel);
            Canvas.SetZIndex(this.mainTextPanel, 2);
        }

        #endregion


        #region 字段与属性===================================================================================================

        /// <summary>
        /// [只读]返回右下角坐标。
        /// </summary>
        public override Point BottomRight
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(startPoint.X, endPoint.X);
                maxRight = Math.Max(startPoint.X, endPoint.X);

                minTop = Math.Min(startPoint.Y, endPoint.Y);
                maxBottom = Math.Max(startPoint.Y, endPoint.Y);

                return new Point(maxRight, maxBottom);
            }
        }
        
        /// <summary>
        /// 点划线定义。
        /// </summary>
        private static DoubleCollection dashArray;
        
        private Point endPoint = new Point();
        /// <summary>
        /// [读写]起点。
        /// </summary>
        [Tools.LunarProperty("EndPoint", PropertyDateType.Point)]
        public Point EndPoint
        {
            get { return endPoint; }
            set
            {
                endPoint = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndPointTag, value.ToString());
                }

                RefreshLocation();
            }
        }

        /// <summary>
        /// [只读]表示当前部件是否被某个连接线挂接着。
        /// </summary>
        public bool IsLinked
        {
            get
            {
                if (this.masterEditor == null) return false;

                foreach (UIElement ue in this.masterEditor.Children)
                {
                    ILinkableLine linkedLine = ue as ILinkableLine;
                    if (linkedLine == null) continue;

                    if (linkedLine.StartMasterId == this.id || linkedLine.EndMasterId == this.id) return true;
                }

                return false;
            }
        }
        
        private Ellipse mainEllipse = new Ellipse() { Cursor = Cursors.Hand };
        /// <summary>
        /// [只读]用以呈现的椭圆。
        /// </summary>
        public Ellipse MainEllipse
        {
            get { return mainEllipse; }
        }
        
        private Point StartBasePoint
        {
            get
            {
                return new Point(Math.Min(startPoint.X, endPoint.X), Math.Min(startPoint.Y, endPoint.Y));
            }
        }
        
        private Point startPoint = new Point();
        /// <summary>
        /// [读写]起点。
        /// </summary>
        [Tools.LunarProperty("StartPoint", PropertyDateType.Point)]
        public Point StartPoint
        {
            get { return startPoint; }
            set
            {
                startPoint = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartPointTag, value.ToString());
                }

                RefreshLocation();
            }
        }

        private double textRotateAngle = 0;
        /// <summary>
        /// [读写]文本旋转角度。取值范围：[-180,180]。
        /// </summary>
        [Tools.LunarProperty("TextRotateAngle", PropertyDateType.Double)]
        public double TextRotateAngle
        {
            get { return textRotateAngle; }
            set
            {
                if (value > 180)
                {
                    textRotateAngle = 180;
                }
                else if (value < -180)
                {
                    textRotateAngle = -180;
                }
                else
                {
                    textRotateAngle = value;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.TextRotateAngleTag, textRotateAngle.ToString());
                }

                this.RefreshTextRotateAngle();
            }
        }

        /// <summary>
        /// [只读]返回圆路径对象的左上角坐标。
        /// </summary>
        public override Point TopLeft
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(startPoint.X, endPoint.X);
                maxRight = Math.Max(startPoint.X, endPoint.X);

                minTop = Math.Min(startPoint.Y, endPoint.Y);
                maxBottom = Math.Max(startPoint.Y, endPoint.Y);

                return new Point(minLeft, minTop);
            }
        }

        #endregion


        #region 方法=========================================================================================================

        public override void Build()
        {
            base.Build();

            if (this.xmlData == null) return;

            XmlAttribute attrStartPoint = this.xmlData.GetAttribute(XmlTags.StartPointTag);
            if (attrStartPoint != null)
            {
                this.startPoint = Point.Parse(attrStartPoint.Value);
            }

            XmlAttribute attrEndPoint = this.xmlData.GetAttribute(XmlTags.EndPointTag);
            if (attrEndPoint != null)
            {
                this.endPoint = Point.Parse(attrEndPoint.Value);
            }

            XmlAttribute attrTextRotateAngle = this.xmlData.GetAttribute(XmlTags.TextRotateAngleTag);
            if (attrTextRotateAngle != null)
            {
                this.textRotateAngle = double.Parse(attrTextRotateAngle.Value);
            }

            this.RefreshTextRotateAngle();
            this.RefreshLocation();

            //此类是下面这几个属性的“最终实现类”。这些属性的值都已在基类确定。因此调用,
            this.RefreshWidgetBackColor();
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();
        }
        
        public void DrawLine()
        {
            if (masterEditor == null) return;

            DrawLine(this.startPoint, this.endPoint, false);
        }

        /// <param name="startPoint">首端点。</param>
        /// <param name="endPoint">尾端点。</param>
        /// <param name="isShift">是否按住Shift键拖动。</param>
        private void DrawLine(Point startPoint, Point endPoint, bool isShift)
        {
            Point startBasePt, endBasePt;

            startBasePt = new Point(Math.Min(startPoint.X, endPoint.X),
                   Math.Min(startPoint.Y, endPoint.Y));
            endBasePt = new Point(Math.Max(startPoint.X, endPoint.X),
              Math.Max(startPoint.Y, endPoint.Y));

            if (isShift)
            {
                if (startPoint.Y > endPoint.Y)
                {
                    endBasePt.Y = startBasePt.Y + (endBasePt.X - startBasePt.X);
                }
                else
                {
                    startBasePt.Y = endBasePt.Y - (endBasePt.X - startBasePt.X);
                }
            }

            Canvas.SetLeft(mainEllipse, startBasePt.X);
            Canvas.SetTop(mainEllipse, startBasePt.Y);

            mainEllipse.Width = (endBasePt.X - startBasePt.X);
            mainEllipse.Height = (endBasePt.Y - startBasePt.Y);
            
            LocateTextPanel(startBasePt, endBasePt);
        }

        /// <summary>
        /// 重定文本位置。
        /// </summary>
        /// <param name="startBasePt">首基准点。</param>
        /// <param name="endBasePt">尾基准点。</param>
        private void LocateTextPanel(Point startBasePt, Point endBasePt)
        {


            Point center = new Point(startBasePt.X + (endBasePt.X - startBasePt.X) / 2,
                startBasePt.Y + (endBasePt.Y - startBasePt.Y) / 2);

            Point textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left,
                center.Y - this.mainTextPanel.ActualHeight / 2 - this.mainTextPanel.Margin.Top);

            Canvas.SetLeft(this.mainTextPanel, textStart.X);
            Canvas.SetTop(this.mainTextPanel, textStart.Y);
        }
        
        /// <summary>
        /// 取与自身挂接的连接线。
        /// </summary>
        /// <returns>可能返回null。</returns>
        public List<ILinkableLine> GetLinkedLines()
        {
            if (this.masterEditor == null) return null;

            List<Widget> widgets = new List<Widget>();
            widgets.Add(this);

            return this.masterEditor.GetLinkedLines(widgets);
        }

        public override string GetRelativeOuterXml(Point baseCopyTopLeft)
        {
            if (this.xmlData == null) return string.Empty;

            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseCopyTopLeft.X,
                oldStartPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.StartPointTag, newStartPoint.ToString());

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseCopyTopLeft.X,
                oldEndPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.EndPointTag, newEndPoint.ToString());

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(this.xmlData.OuterXml);

            this.xmlData.SetAttribute(XmlTags.StartPointTag, oldStartPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.EndPointTag, oldEndPoint.ToString());

            return sb.ToString();
        }

        /// <summary>
        /// 这个虚方法是用以查看本部件是否在选定框的内部。
        /// 线型部件，各有各的计算办法。
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        public override bool IsInRect(Rect rect)
        {
            //return base.IsInRect(rect);//这个要屏蔽。
            bool isInRect = base.IsInRect(rect);
            if (isInRect)
            {
                return true;
            }
            else
            {
                Rect virtualRect = new Rect(startPoint, endPoint);
                return rect.IntersectsWith(virtualRect);
            }
        }
        
        public override void RefreshLineDash()
        {
            switch (lineDash)
            {
                case LineDashType.DashType.Dash:
                    {
                        this.mainEllipse.StrokeDashArray = LineDashType.dashCollection; break;
                    }
                case LineDashType.DashType.DashDotDot:
                    {
                        this.mainEllipse.StrokeDashArray = LineDashType.dashDotDotCollection; break;
                    }
                case LineDashType.DashType.Dot:
                    {
                        this.mainEllipse.StrokeDashArray = LineDashType.dotCollection; break;
                    }
                case LineDashType.DashType.Solid:
                    {
                        this.mainEllipse.StrokeDashArray = LineDashType.solidCollection; break;
                    }
                default:
                    {
                        this.mainEllipse.StrokeDashArray = LineDashType.dashDotCollection; break;
                    }
            }
        }

        public override void RefreshWidgetLineWidth()
        {
            mainEllipse.StrokeThickness = widgetLineWidth;
        }

        public override void RefreshLocation()
        {
            base.RefreshLocation();

            DrawLine();

            //Point startBasePt = StartBasePoint;
            //Point endBasePt = EndBasePoint;
            //Canvas.SetLeft(mainEllipse, startBasePt.X);
            //Canvas.SetTop(mainEllipse, startBasePt.Y);

            //mainEllipse.Width = (endBasePt.X - startBasePt.X);
            //mainEllipse.Height = (endBasePt.Y - startBasePt.Y);

            //this.movingRect = new Rect(startPoint, endPoint);

            RefreshWidgetLineWidth();
            this.RefreshTextRotateAngle();
        }

        public override void RefreshPointWhenGroupIn(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseTopLeft.X,
                oldStartPoint.Y - baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseTopLeft.X,
                oldEndPoint.Y - baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public override void RefreshPointWhenGroupOut(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X + baseTopLeft.X,
                oldStartPoint.Y + baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X + baseTopLeft.X,
                oldEndPoint.Y + baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public override void RefreshIsShadowVisible()
        {
            //base.RefreshIsShadowVisible();//保持文本清晰

            if (isShadowVisible)
            {
                this.mainEllipse.Effect = Widget.ShadowEffect;
            }
            else
            {
                this.mainEllipse.Effect = null;
            }
        }

        private Point EndBasePoint
        {
            get
            {
                return new Point(Math.Max(startPoint.X, endPoint.X), Math.Max(startPoint.Y, endPoint.Y));
            }
        }

        public override void RefreshTextPanelLocatin()
        {
            LocateTextPanel(this.StartBasePoint, this.EndBasePoint);
        }

        /// <summary>
        /// 刷新文本区旋转角度。
        /// </summary>
        public void RefreshTextRotateAngle()
        {
            if (this.mainTextPanel.RenderTransformOrigin != DefaultRenderCenter)
            {
                this.mainTextPanel.RenderTransformOrigin = DefaultRenderCenter;
            }

            if (this.textRotateAngle == 0)
            {
                this.mainTextPanel.RenderTransform = DefaultRotateTransform;
            }
            else
            {
                this.mainTextPanel.RenderTransform = new RotateTransform(textRotateAngle);
            }
        }

        public override void RefreshWidgetBackColor()
        {
            base.RefreshWidgetBackColor();
            if (widgetBackColor == Brushes.Transparent)
            {
                this.mainEllipse.Fill = null;
            }
            else
            {
                this.mainEllipse.Fill = widgetBackColor;
            }
        }

        public override void RefreshWidgetLineColor()
        {
            this.mainEllipse.Stroke = widgetLineColor;
        }

        #endregion


        #region 其它=========================================================================================================


        private enum ControlDraggingType { Start, CenterCP, End, None }

        #endregion
    }
}
